using System.Text;
using System.Text.Json;
using BuildingBlocks.Abstractions.EventBase;
using Microsoft.Extensions.DependencyInjection;
using RabbitMQ.Client;
using RabbitMQ.Client.Events;

namespace BuildingBlocks.Infrastructure.EventBus.RabbitMQ;

public class RabbitMQEventBus : IEventBus
{
    private readonly IRabbitMQPersistentConnection _connection;
    private readonly IServiceProvider _serviceProvider;
    private readonly Dictionary<string, List<Type>> _handlers = new();
    private readonly Dictionary<string, Type> _eventTypes = new();

    public RabbitMQEventBus(IRabbitMQPersistentConnection connection, IServiceProvider serviceProvider)
    {
        _connection = connection;
        _serviceProvider = serviceProvider;
    }

    public async Task PublishAsync(IntegrationEvent @event)
    {
        var eventName = @event.GetType().Name;

        if (!_connection.IsConnected)
        {
            _connection.TryConnect();
        }

        using var channel = _connection.CreateModel();
        channel.ConfirmSelect(); // 开启发布确认模式

        channel.QueueDeclare(eventName, durable: true, exclusive: false, autoDelete: false, arguments: null);

        var body = JsonSerializer.SerializeToUtf8Bytes(@event, @event.GetType());

        channel.BasicPublish(
            exchange: "",
            routingKey: eventName,
            basicProperties: null,
            body: body);

        // 等待 Broker 确认，异步版本
        await Task.Run(() => channel.WaitForConfirmsOrDie());
    }

    public void Subscribe<T, TH>()
        where T : IntegrationEvent
        where TH : IIntegrationEventHandler<T>
    {
        var eventName = typeof(T).Name;
        var handlerType = typeof(TH);

        if (!_handlers.ContainsKey(eventName))
        {
            _handlers[eventName] = new List<Type>();
        }

        if (_handlers[eventName].Any(x => x == handlerType)) return;

        _handlers[eventName].Add(handlerType);
        _eventTypes[eventName] = typeof(T);

        StartBasicConsume(eventName);
    }

    private void StartBasicConsume(string eventName)
    {
        if (!_connection.IsConnected)
        {
            _connection.TryConnect();
        }

        var channel = _connection.CreateModel();
        channel.QueueDeclare(eventName, true, false, false, null);

        var consumer = new AsyncEventingBasicConsumer(channel);
        consumer.Received += async (model, ea) =>
        {
            try
            {
                Console.WriteLine($"[RabbitMQEventBus] 收到消息，队列：{eventName}");
                var message = Encoding.UTF8.GetString(ea.Body.Span);

                if (!_eventTypes.TryGetValue(eventName, out var eventType))
                {
                    Console.WriteLine($"[RabbitMQEventBus] 未知事件类型: {eventName}");
                    channel.BasicAck(ea.DeliveryTag, false);
                    return;
                }

                var integrationEvent = JsonSerializer.Deserialize(message, eventType);

                if (_handlers.TryGetValue(eventName, out var handlerTypes))
                {
                    using var scope = _serviceProvider.CreateScope();

                    var tasks = handlerTypes.Select(handlerType =>
                    {
                        // 构建泛型接口类型 IIntegrationEventHandler<eventType>
                        var handlerInterface = typeof(IIntegrationEventHandler<>).MakeGenericType(eventType);

                        // 从 DI 获取接口实例
                        var handler = scope.ServiceProvider.GetService(handlerInterface);
                        if (handler == null) return Task.CompletedTask;

                        // 通过反射获取 HandleAsync 方法
                        var handleMethod = handlerInterface.GetMethod("HandleAsync");
                        if (handleMethod == null) return Task.CompletedTask;

                        // 调用 HandleAsync 并返回 Task
                        var task = (Task)handleMethod.Invoke(handler, new object[] { integrationEvent });
                        return task;
                    });

                    await Task.WhenAll(tasks);
                }
                channel.BasicAck(ea.DeliveryTag, false);
                Console.WriteLine($"[RabbitMQEventBus] 事件处理完成，已Ack");
            }
            catch (Exception ex)
            {
                Console.WriteLine($"[RabbitMQEventBus] 事件处理异常: {ex}");
                // 可以记录日志或推送到死信队列
                channel.BasicAck(ea.DeliveryTag, false); // 根据业务决定是否 ack
            }
        };

        channel.BasicConsume(queue: eventName, autoAck: false, consumer: consumer);
    }
}